/*
The MIT License (MIT)

Copyright (c) 2014 Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once

#include "hhdGfxTypes.h"
#include "hhdVector.hpp"

namespace hhd
{
	enum GfxFillMode
	{
		FM_WIREFRAME,
		FM_FILL
	};

	enum GfxCullMode
	{
		CM_NO_CULL,
		CM_FRONT,
		CM_BACK
	};

	struct GfxRasterizationStateConfig
	{
		GfxFillMode fill_mode;
		GfxCullMode cull_mode;
		bool counter_clockwise_winding;
		int32_t depth_bias;
		float depth_bias_clamp;
		float sloped_scaled_depth_bias;
		bool depth_clip_enabled;
		bool scissor_enabled;
		// add MSAA features as needed ...
	};

	enum GfxBlendFactor
	{
		BW_ZERO,
		BW_ONE,

		BW_SOURCE_COLOR,
		BW_INVERSE_SOURCE_COLOR,

		BW_SOURCE_ALPHA,
		BW_INVERSE_SOURCE_ALHPA,

		BW_DESTINATION_COLOR,
		BW_INVERSE_DESTINATION_COLOR,

		BW_DESTINATION_ALPHA,
		BW_INVERSE_DESTINATION_ALHPA,

		BW_BLEND_FACTOR,
		BW_INVERSE_BLEND_FACTOR
	};

	enum GfxBlendOperator
	{
		BO_ADD,
		BO_SUBTRACT_SOURCE_FROM_DESTINATION,
		BO_SUBTRACT_DESTINATION_FROM_SOURCE,
		BO_MIN,
		BO_MAX
	};

	struct GfxAlphaBlendStateConfig
	{
		flag_t blend_enabled;

		GfxBlendFactor source_color_blend_factor;
		GfxBlendFactor destination_color_blend_factor;
		GfxBlendOperator color_blend_operator;

		GfxBlendFactor source_alpha_blend_factor;
		GfxBlendFactor destination_alpha_blend_factor;
		GfxBlendOperator alpha_blend_operator;

		uint8_t render_target_write_mask;
	};

	enum GfxComparisonFunction
	{
		CF_NEVER,
		CF_LESS,
		CF_EQUAL,
		CF_LESS_THAN_OR_EQUAL,
		CF_GREATER,
		CF_NOT_EQUAL,
		CF_GREATER_THAN_OR_EQUAL,
		CF_ALWAYS
	};

	enum GfxStencilOperation
	{
		SO_KEEP,
		SO_ZERO,
		SO_REPLACE,
		SO_INCREMENT_CLAMP,
		SO_DECREMENT_CLAMP,
		SO_INVERT,
		SO_INCREMENT_WRAP,
		SO_DECREMENT_WRAP
	};

	struct GfxDepthOrStencilFailOperationConfig
	{
		GfxStencilOperation stencil_fails_operation;
		GfxStencilOperation depth_fails_stencil_passes_operation;
		GfxStencilOperation both_pass_operation;
		GfxComparisonFunction compare_function;
	};

	struct GfxDepthStencilStateConfig
	{
		flag_t depth_enabled;
		flag_t depth_write_enabled;
		GfxComparisonFunction depth_comparison_function;

		flag_t stencil_enabled;
		uint8_t stencil_read_mask;
		uint8_t stencil_write_mask;

		GfxDepthOrStencilFailOperationConfig front_face;
		GfxDepthOrStencilFailOperationConfig back_face;
	};

	enum GfxFilterType
	{
		FT_MIN_MAG_MIP_POINT,
		FT_MIN_MAG_MIP_LINEAR,
		FT_MIN_MAG_MIP_ANISOTROPIC
		// Add more as needed
	};

	enum GfxTextureAddressMode
	{
		TAM_WRAP,
		TAM_MIRROR,
		TAM_CLAMP,
		TAM_BORDER,
		TAM_MIRROR_ONCE
	};

	struct GfxSamplerStateConfig
	{
		GfxFilterType filter_type;
		GfxTextureAddressMode u_mode;
		GfxTextureAddressMode v_mode;
		GfxTextureAddressMode w_mode;
		float mip_lod_bias;
		uint8_t max_anisotropy;
		GfxComparisonFunction comparison_function;
		Color border_color;
		float min_lod;
		float max_lod;
	};

	class GfxRenderState
	{
	public:
		GfxRenderState( const GfxRasterizationStateConfig& in_rasterization_state,
			const GfxAlphaBlendStateConfig& in_alpha_blend_state,
			const GfxDepthStencilStateConfig& in_depth_stencil_state);

		GfxHandle GetRasterizationState() const { return _gpu_rasterization_state; }
		GfxHandle GetAlphaBlendState() const { return _gpu_alpha_blend_state; }
		GfxHandle GetDepthStencilState() const { return _gpu_depth_stencil_state; }

	protected:
		GfxRenderState();

	private:
		GfxHandle _gpu_rasterization_state;
		GfxHandle _gpu_alpha_blend_state;
		GfxHandle _gpu_depth_stencil_state;
	};
}